﻿
/// <summary>
/// Made by Team 6.
/// This class holds the the algorithm for the complete program.
/// It is divided in 4 sections, 
/// 1:Localisation ( for localizing the number plate ) - made by group 3
/// 2:Lighting ( for optimizing the localized numberplate for segmentation ) - made by group 7
/// 3: segmentation ( used for segmenting the characters on the numberplate ) - made by group 6
/// 4: optical character recognition ( used for recognizing the segmented characters ) - made by group 9 
/// </summary>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.Drawing.Imaging;

namespace KentekenHerkenning
{
    class LicensePlateRecognition
    {
        /// <summary>
        /// This function is the main 'loop' for processing an image of a car to a sequence of characters
        /// which represent the number plate using a TestsetImage to hold the data. (each TestsetImage will hold 1 number plate)
        /// </summary>
        /// <param name="tsi">The testsetimage to be used</param>
        /// <returns>An result object, holding the final calculated results of the algorithm.</returns>
        public static Result processImage(TestsetImage tsi)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();

            Result testImageResult = new Result();
            Bitmap WorkImage = new Bitmap(tsi.SourceImage);

            NumberPlate numberplate;

            #region localisation

            Bitmap mhhs = MeanHSVAlgorithm.DoAlgorithm(WorkImage);
            bool equal = false; //equal houd bij of er equalisatie is uitgevoerd op het plaatje
            Bitmap equalized;

            if (MeanHSVAlgorithm.Hue < 130.0 || MeanHSVAlgorithm.Saturation < 0.21) // Als het plaatje donker is.
            {
                EqualisationAlgorithm eq = new EqualisationAlgorithm();
                equal = true;
                equalized = EqualisationAlgorithm.DoAlgorithm(WorkImage); // voert equalisation op plaatje uit om hem lichter te maken
            }
            else // als het plaatje licht is equalizatie niet nodig
            {
                equalized = WorkImage;
            }

            LocateLicensePlate loc = new LocateLicensePlate();
            WorkImage = loc.DoAlgorithm(equalized);

            int Height = WorkImage.Height;
            int Width = WorkImage.Width;
            int size = Width * Height;

            if (Height * 2 > Width || size < 50) //Kijkt of een mogelijk nummerbord is gevonden
            // height/width is verhouding van nummerbord, als het plaatje onder de 50 pixels heeft kan er nooit ocr op toegepast worden
            {
                if (!equal) // Als er geen mogelijk nummerbord is gevonden kijkt hij of er voorgaand equalisation is gebruikt.
                { //Equalisation word toegepast als deze voorheen niet was toegepast
                    equalized = EqualisationAlgorithm.DoAlgorithm(WorkImage);
                }
                else if (equal) // als er wel equalisation was gebruikt dan probeert hij nog een keer het nummerbord te
                { //lokalizeren zonder equalisatie
                    equalized = WorkImage;
                }
                WorkImage = loc.DoAlgorithm(equalized); //voert het locate algoritme weer uit
            }

            Point UL = loc.upperLeft;
            
            numberplate = new NumberPlate(loc.upperLeft,loc.upperRight,loc.downLeft,loc.upperRight);

            #endregion

            #region lightning
            //lightning here
            LightingFixer LF = new LightingFixer();
            WorkImage = LF.FixLightingToNewImage(WorkImage);
            #endregion

            CornerCoordinates cc = new CornerCoordinates(WorkImage);
            Point[] points = cc.GetCornerCoordinates();

            #region segmentation
            //segmentation here

            List<Blob> blobbers = new List<Blob>();
            List<Bitmap> Characterlist = new List<Bitmap>();

            blobbers = BlobDetection.doAlgorithm(WorkImage);
            int resultCounter = 0;

            blobbers.Sort((x, y) => x.minx.CompareTo(y.minx));

            int pixels = WorkImage.Width * WorkImage.Height;

            foreach (Blob b in blobbers)
            {
                if (b.amountOfPixels < pixels / 3000)
                    continue;

                if (b.maxx - b.minx < 5)
                    continue;

                if (b.minx <= 10)
                    continue;
                if (b.maxx > (WorkImage.Width - 10))
                    continue;
               
                if (b.maxy - b.miny < WorkImage.Height / 4)
                    continue;



                if (((b.maxy - b.miny) / 1.2) < (b.maxx - b.minx))
                    continue;

                if (!(Math.Abs(b.maxx - b.minx) > Math.Abs(b.maxy - b.miny)))
                {
                    PixelPoint tempx = new PixelPoint(b.minx, b.miny, 231, 0, 0, 0);
                    PixelPoint tempy = new PixelPoint(b.maxx, b.maxy, 231, 0, 0, 0);

                    try
                    {
                        Bitmap temp = WorkImage.crop(b.minx, b.maxx, b.miny, b.maxy);
                    }
                    catch (Exception)
                    {
                        
                    }
                    resultCounter++;
                }
            }

            if (Characterlist.Count == 0)
            {

                foreach (Blob b in blobbers)
                {
                    if (b.amountOfPixels < pixels / 1150)
                        continue;

                    if (b.maxx - b.minx < 5)
                        continue;

                    if (b.minx <= 10)
                        continue;

                    if (b.maxx > (WorkImage.Width - 10))
                        continue;

                    if (b.maxy - b.miny < WorkImage.Height / 4)
                        continue;

                    if (((b.maxy - b.miny) / 1.2) < (b.maxx - b.minx))
                        continue;

                    if (!(Math.Abs(b.maxx - b.minx) > Math.Abs(b.maxy - b.miny)))
                    {
                        PixelPoint tempx = new PixelPoint(b.minx, b.miny, 231, 0, 0, 0);
                        PixelPoint tempy = new PixelPoint(b.maxx, b.maxy, 231, 0, 0, 0);

                        try
                        {
                            Bitmap temp = WorkImage.crop(b.minx, b.maxx, b.miny, b.maxy);
                            Characterlist.Add(temp);
                        }
                        catch (Exception)
                        {
                            
                        }
                        WorkImage = DrawRectangles.drawRectangle(WorkImage, tempx, tempy);
                        resultCounter++;
                    }
                }

            }
            


            

            #endregion

            #region OCR
            //OCR here
            
            //returns per char list met doubles ( waardes voor meest likely char )

            //geef in een for loop chars mee, kijk naar hoogste waarde en gooi ze door de functie van dylan

            List<Char> LPList = new List<char>();

                foreach (Bitmap b in Characterlist)
                {
                    //Do algortime
                    //Haal hoogste eruit
                    //convert hem naar char

                    double[] temp = new double[36];

                    temp = OCR.DoOCR(b);

                    int highestIndex = 0;
                    double highestDouble = 0;

                    for (int i = 0; i < temp.Length; i++)
                    {
                        if (temp[i] > highestDouble)
                        {
                            highestIndex = i;
                            highestDouble = temp[i];
                        }
                    }

                    LPList.Add(OCR.indexToCharacter(highestIndex));
                   
                }
                try
                {

                    string s = "";
                    foreach (char c in LPList)
                    {
                        s += c;
                    }

                    numberplate.DetectedCharacters = s;
                    Debug.WriteLine(s);
                    sw.Stop();
                 
                    Point ULT = loc.upperLeft;
                    
                    testImageResult.TopLeft = new Point(ULT.X + points[0].X,ULT.Y + points[0].Y);
                    testImageResult.TopRight = new Point(ULT.X + points[1].X, ULT.Y + points[1].Y);
                    testImageResult.BottomLeft = new Point(ULT.X + points[3].X,ULT.Y + points[3].Y);
                    testImageResult.BottomRight = new Point(ULT.X + points[2].X,ULT.Y + points[2].Y);
                    testImageResult.SupposedTopLeft = tsi.upperleft;
                    testImageResult.SupposedTopRight = tsi.upperright;
                    testImageResult.SupposedBottomLeft = tsi.lowerleft;
                    testImageResult.SupposedBottomRight = tsi.lowerright;
                    testImageResult.originalPath = tsi.fileName;
                    System.IO.Directory.CreateDirectory(System.Reflection.Assembly.GetExecutingAssembly().Location.Replace("FinalKentekenHerkenning.exe", "") + "Images");
                    WorkImage.Save(System.Reflection.Assembly.GetExecutingAssembly().Location.Replace("FinalKentekenHerkenning.exe","")+ "Images/" + tsi.fileName.Replace(".jpg", ".bmp").Replace(".JPG", ".bmp"), ImageFormat.Bmp);
                    testImageResult.filePath = System.Reflection.Assembly.GetExecutingAssembly().Location.Replace("FinalKentekenHerkenning.exe", "") + "Images/" + tsi.fileName.Replace(".jpg", ".bmp").Replace(".JPG", ".bmp");
                    testImageResult.foundLicensePlate = s;
                    testImageResult.supposedLicencePLate = tsi.originalCharacters[0].Replace("-", "");
                    testImageResult.Time = (int)sw.ElapsedMilliseconds;
                    testImageResult.CorrectPercentage = (int)ResultFunctions.measureOcrPrecision(tsi.originalCharacters, new String[1] { numberplate.DetectedCharacters });
                    testImageResult.matchingCharacters = ResultFunctions.compareString(tsi.originalCharacters[0], numberplate.DetectedCharacters);

                }
                catch{}

            Characterlist.Clear();
            #endregion

            return testImageResult;
        }
    }
}
